package com.hanserwei.community.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hanserwei.community.entity.po.House;
import com.hanserwei.community.entity.po.Owner;
import com.hanserwei.community.entity.po.PropertyInfo;
import com.hanserwei.community.entity.po.PropertyType;
import com.hanserwei.community.entity.request.property.PropertyFeeQueryRequest;
import com.hanserwei.community.entity.request.property.PropertyFeeSaveRequest;
import com.hanserwei.community.entity.vo.HouseVO;
import com.hanserwei.community.entity.vo.OwnerBriefVO;
import com.hanserwei.community.entity.vo.PropertyFeeVO;
import com.hanserwei.community.enums.ResponseCodeEnum;
import com.hanserwei.community.mapper.PropertyInfoMapper;
import com.hanserwei.community.service.HouseService;
import com.hanserwei.community.service.OwnerService;
import com.hanserwei.community.service.PropertyFeeService;
import com.hanserwei.community.service.PropertyTypeService;
import com.hanserwei.community.uitils.ThrowUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

@Service
@RequiredArgsConstructor
public class PropertyFeeServiceImpl extends ServiceImpl<PropertyInfoMapper, PropertyInfo> implements PropertyFeeService {

    private final PropertyTypeService propertyTypeService;
    private final HouseService houseService;
    private final OwnerService ownerService;

    @Override
    public Page<PropertyFeeVO> pagePropertyFees(PropertyFeeQueryRequest request) {
        Page<PropertyInfo> page = new Page<>(request.getCurrent(), request.getPageSize());
        QueryWrapper<PropertyInfo> queryWrapper = buildQueryWrapper(request);
        Page<PropertyInfo> propertyPage = page(page, queryWrapper);
        List<PropertyFeeVO> voList = convertToVOList(propertyPage.getRecords());
        Page<PropertyFeeVO> voPage = new Page<>(propertyPage.getCurrent(), propertyPage.getSize(), propertyPage.getTotal());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    public PropertyFeeVO getPropertyFeeDetail(Integer id) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "收费记录ID参数错误！");
        PropertyInfo info = getById(id);
        ThrowUtils.throwIf(info == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "收费记录不存在！");
        List<PropertyFeeVO> list = convertToVOList(Collections.singletonList(info));
        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public boolean createPropertyFee(PropertyFeeSaveRequest request) {
        validateSaveRequest(request);
        PropertyInfo info = new PropertyInfo();
        BeanUtils.copyProperties(request, info);
        boolean result = save(info);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "新增失败！");
        return true;
    }

    @Override
    public boolean updatePropertyFee(Integer id, PropertyFeeSaveRequest request) {
        ThrowUtils.throwIf(id == null || id <= 0, ResponseCodeEnum.INVALID_PARAMETER, "收费记录ID参数错误！");
        validateSaveRequest(request);
        PropertyInfo dbInfo = getById(id);
        ThrowUtils.throwIf(dbInfo == null, ResponseCodeEnum.RESOURCE_NOT_FOUND, "收费记录不存在！");
        BeanUtils.copyProperties(request, dbInfo);
        dbInfo.setId(id);
        boolean result = updateById(dbInfo);
        ThrowUtils.throwIf(!result, ResponseCodeEnum.SYSTEM_ERROR, "更新失败！");
        return true;
    }

    private void validateSaveRequest(PropertyFeeSaveRequest request) {
        ThrowUtils.throwIf(request == null, ResponseCodeEnum.INVALID_PARAMETER, "参数错误！");
        ThrowUtils.throwIf(request.getTypeId() == null || request.getTypeId() <= 0, ResponseCodeEnum.INVALID_PARAMETER, "收费类型不能为空！");
        ThrowUtils.throwIf(request.getHouseId() == null || request.getHouseId() <= 0, ResponseCodeEnum.INVALID_PARAMETER, "关联房屋不能为空！");
        PropertyType propertyType = propertyTypeService.getById(request.getTypeId());
        ThrowUtils.throwIf(propertyType == null, ResponseCodeEnum.INVALID_PARAMETER, "收费类型不存在！");
        House house = houseService.getById(request.getHouseId());
        ThrowUtils.throwIf(house == null, ResponseCodeEnum.INVALID_PARAMETER, "关联房屋不存在！");
        BigDecimal money = request.getMoney();
        ThrowUtils.throwIf(money == null || money.signum() < 0, ResponseCodeEnum.INVALID_PARAMETER, "收费金额不能小于0！");
        LocalDateTime start = request.getStartDate();
        LocalDateTime end = request.getEndDate();
        if (start != null && end != null) {
            ThrowUtils.throwIf(start.isAfter(end), ResponseCodeEnum.INVALID_PARAMETER, "开始日期不能晚于结束日期！");
        }
    }

    private QueryWrapper<PropertyInfo> buildQueryWrapper(PropertyFeeQueryRequest request) {
        QueryWrapper<PropertyInfo> wrapper = new QueryWrapper<>();
        if (request == null) {
            return wrapper;
        }
        wrapper.eq(request.getId() != null && request.getId() > 0, "id", request.getId());
        wrapper.eq(request.getTypeId() != null && request.getTypeId() > 0, "type_id", request.getTypeId());
        wrapper.eq(request.getHouseId() != null && request.getHouseId() > 0, "house_id", request.getHouseId());
        wrapper.eq(request.getStatus() != null, "status", request.getStatus());
        if (request.getOwnerId() != null && request.getOwnerId() > 0) {
            Owner owner = ownerService.getById(request.getOwnerId());
            if (owner == null || owner.getHouseId() == null) {
                wrapper.apply("1 = 0");
            } else {
                wrapper.eq("house_id", owner.getHouseId());
            }
        }
        if (StringUtils.hasText(request.getOwnerName())) {
            List<Owner> owners = ownerService.lambdaQuery()
                    .like(Owner::getUserName, request.getOwnerName())
                    .select(Owner::getHouseId)
                    .list();
            List<Integer> houseIds = owners.stream()
                    .map(Owner::getHouseId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .toList();
            if (houseIds.isEmpty()) {
                wrapper.apply("1 = 0");
            } else {
                wrapper.in("house_id", houseIds);
            }
        }
        wrapper.ge(request.getStartDateFrom() != null, "start_date", request.getStartDateFrom());
        wrapper.le(request.getStartDateTo() != null, "start_date", request.getStartDateTo());
        wrapper.ge(request.getEndDateFrom() != null, "end_date", request.getEndDateFrom());
        wrapper.le(request.getEndDateTo() != null, "end_date", request.getEndDateTo());
        wrapper.like(StringUtils.hasText(request.getRemarks()), "remarks", request.getRemarks());
        wrapper.orderBy(StringUtils.hasText(request.getSortField()), !"descend".equalsIgnoreCase(request.getSortOrder()), request.getSortField());
        return wrapper;
    }

    private List<PropertyFeeVO> convertToVOList(List<PropertyInfo> records) {
        if (CollectionUtils.isEmpty(records)) {
            return Collections.emptyList();
        }
        Set<Integer> typeIds = records.stream()
                .map(PropertyInfo::getTypeId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, PropertyType> typeMap = typeIds.isEmpty() ? Collections.emptyMap() :
                propertyTypeService.listByIds(typeIds).stream()
                        .collect(Collectors.toMap(PropertyType::getId, type -> type));

        Set<Integer> houseIds = records.stream()
                .map(PropertyInfo::getHouseId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Integer, HouseVO> houseMap = houseIds.isEmpty() ? Collections.emptyMap() :
                houseService.getHouseVOList(houseService.listByIds(houseIds)).stream()
                        .collect(Collectors.toMap(HouseVO::getId, houseVO -> houseVO));

        Map<Integer, Owner> ownerMap = houseIds.isEmpty() ? Collections.emptyMap() :
                ownerService.lambdaQuery()
                        .in(!houseIds.isEmpty(), Owner::getHouseId, houseIds)
                        .list()
                        .stream()
                        .collect(Collectors.toMap(Owner::getHouseId, owner -> owner, (a, b) -> a));

        return records.stream().map(info -> {
            PropertyFeeVO vo = new PropertyFeeVO();
            BeanUtils.copyProperties(info, vo);
            vo.setHouseId(info.getHouseId());
            if (info.getTypeId() != null) {
                PropertyType type = typeMap.get(info.getTypeId());
                if (type != null) {
                    vo.setTypeName(type.getName());
                    vo.setTypePrice(type.getPrice());
                    vo.setTypeUnit(type.getUnit());
                }
            }
            if (info.getHouseId() != null) {
                vo.setHouse(houseMap.get(info.getHouseId()));
                Owner owner = ownerMap.get(info.getHouseId());
                if (owner != null) {
                    vo.setOwner(toOwnerBrief(owner));
                }
            }
            return vo;
        }).toList();
    }

    private OwnerBriefVO toOwnerBrief(Owner owner) {
        if (owner == null) {
            return null;
        }
        return OwnerBriefVO.builder()
                .id(owner.getId())
                .name(owner.getUserName())
                .tel(owner.getTel())
                .houseId(owner.getHouseId())
                .build();
    }
}
